using System;
using System.ComponentModel;
using System.Data.SQLite;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using Jonathan.Classes;
using Jonathan.Controls;
using System.Xml.Serialization;
using System.IO;
using System.Collections.Generic;
using Jonathan.Tabber;

namespace Jonathan
{
   /// <summary>
   /// Jonathan's Main Form.
   /// </summary>
   public partial class FrmMain : Form
   {
      /// <summary>
      /// Jonathan Application Options and saved data.
      /// </summary>
      private readonly CjData m_ProgramData;

      /// <summary>
      /// List of Other Text's Chapters and Abbreveations.
      /// </summary>
      public static Dictionary<string, string> OtherTexts;

      #region - Constructor -

      /// <summary>
      /// Creates a new Main form...
      /// </summary>
      public FrmMain ()
      {
         InitializeComponent ();

         // Load Last Configuration...
         OtherTexts = new Dictionary<string, string> ();
         XmlSerializer ser = new XmlSerializer (typeof (CjData));
         using (StreamReader sr = new StreamReader (Common.DataFolder + Common.FILE_PROGRAM_DATA))
         {
            this.m_ProgramData = (CjData)ser.Deserialize (sr);
         }

         this.Location = this.m_ProgramData.Location;

         // Move if needed...
         int w = Screen.AllScreens.Sum (s => s.Bounds.Width);
         if (this.Location.X > w)
            this.Location = new Point (0, 0);

         this.WindowState = this.m_ProgramData.WindowState;
         if (this.WindowState != FormWindowState.Maximized)
            this.Size = this.m_ProgramData.Size;

         if (this.m_ProgramData.MouseOverToolTips)
            this._mnuToolShowTTMouseOver.Checked = true;
         else
            this._mnuToolShowTTClick.Checked = true;

         this._mnuAskToSave.Checked = this.m_ProgramData.AskSaveLayoutOnExit;
         this._mnuSaveOnExit.Checked = this.m_ProgramData.SaveLayoutOnExit;
         this._mnuToolShowVerseBorders.Checked = this.m_ProgramData.ReaderOptions.ShowBorder;
         this._mnuToolHighlightVerse.Checked = this.m_ProgramData.ReaderOptions.HighlightRows;
         this._mnuBookMarks.DropDown = new BookMarkDropDown (this);

         // Add Page Close Event...
         this.m_Tabber.BeforePageClose += MTabberBeforePageClose;
         this.m_Tabber.TabPanelDoubleClick += MTabberTabPanelDoubleClick;

         // Check all the databases...
         this.CheckData ();

         // Load Available Bibles...
         this.LoadBibles ();

         // Load Other Books...
         this.LoadOtherBooks ();

         // Load Reference...
         this.LoadReference ();

         // Load Book Marks...
         this.LoadBookMarks ();

         if (!this.m_ProgramData.SaveLayoutOnExit)
         {
            // Add the Start Tab...
            this.m_Tabber.AddTab (this.GetStartTab ());
         }
         else
         {
            // Load the Last Layout...
            CreateTabberPageDel del = CreateTab;
            if (!this.m_Tabber.LoadLayout (this.m_ProgramData.TabLayoutFile, del))
               this.m_Tabber.AddTab (this.GetStartTab ());
         }
      }

      #endregion

      #region - Properties -

      /// <summary>
      /// Gets the Main Data for the Program...
      /// </summary>
      public CjData ProgramData
      {
         get { return this.m_ProgramData; }
      }

      /// <summary>
      /// Gets the Path to the Default Bible...
      /// </summary>
      public string DefaultBibleFile
      {
         get
         {
            return (from db in this.m_ProgramData.BibleDatabases
                    where db.Name.Equals (this.m_ProgramData.DefaultBible)
                    select Common.DataFolder + db.Path).FirstOrDefault ();
         }
      }

      #endregion

      #region - Set Default Bible -

      /// <summary>
      /// Sets the Default Bible...
      /// </summary>
      /// <param name="sender">Menu Item</param>
      /// <param name="e">Events</param>
      private void SetDefaultBible (object sender, EventArgs e)
      {
         // Get Menu item...
         ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
         if (tsmi != null)
         {
            this.m_ProgramData.DefaultBible = tsmi.Text;

            ToolStripDropDownMenu tsddm = tsmi.Owner as ToolStripDropDownMenu;
            if (tsddm != null)
            {
               for (int a = 0; a < tsddm.Items.Count; a++)
               {
                  ToolStripMenuItem t = (ToolStripMenuItem) tsddm.Items [a];
                  t.Checked = false;
               }
            }

            tsmi.Checked = true;
         }
      }

      #endregion

      #region - Load Data -

      /// <summary>
      /// Creates a tab with the given properties...
      /// </summary>
      /// <param name="tabType">Type of Tab.</param>
      /// <param name="tabTitle">Title of Tab.</param>
      /// <param name="tabInfo">Additional Tab Info.</param>
      /// <returns>Created Tab.</returns>
      public TabberPage CreateTab (string tabType, string tabTitle, string tabInfo)
      {
         if (tabTitle.Equals ("Start"))
         {
            return GetStartTab ();
         }
         if (tabType == typeof (CtrlReader).ToString ())
         {
            string[] versions = tabInfo.Split (new [] { "|" }, StringSplitOptions.RemoveEmptyEntries);
            CtrlReader reader = new CtrlReader (this, versions[0], versions[1]);
            if (versions.Length > 2)
            {
               for (int a = 2; a < versions.Length; a++)
               {
                  reader.AddVersion (versions[a], versions[++a]);
               }
            }
            reader.LoadBookList (false);
            if (tabTitle.Contains ("|"))
            {
               string[] spInfo = tabTitle.Split ('|');
               if (reader.ReaderType == Common.TYPE_BIBLE)
               {
                  reader.SelectPassages (Parser.Parse (spInfo[1].Trim ()));
               }
               else if (reader.ReaderType == Common.TYPE_OTHER)
               {
                  reader.SelectChapter (1, spInfo[1].Trim ().Split (','));
               }
               else if (reader.ReaderType == Common.TYPE_REFERENCE)
               {
                  reader.SelectRefWord (spInfo[1].Trim (), false);
               }
            }
            return reader;
         }
         if (tabType == typeof (CtrlSearch).ToString ())
         {
            CtrlSearch search = new CtrlSearch (this, GetSearchType (tabInfo));
            if (tabTitle.Contains ("|"))
            {
               string[] spInfo = tabTitle.Split ('|');
               search.Search (spInfo[1].Trim ());
            }
            return search;
         }
         if (tabType == typeof (CtrlNote).ToString ())
         {
            CtrlNote note = new CtrlNote ();
            if (!string.IsNullOrEmpty (tabInfo))
               note.OpenFile (tabInfo);

            return note;
         }
         return new TabberPage (tabTitle);
      }

      /// <summary>
      /// Gets the type of search...
      /// </summary>
      /// <param name="searchType">String version of SearchType</param>
      /// <returns>string</returns>
      public static string GetSearchType (string searchType)
      {
         switch (searchType)
         {
            case "Passage":
               return Common.TYPE_PASSAGE;
            case "Reference":
               return Common.TYPE_REFERENCE;
            default:
               return Common.TYPE_BIBLE;
         }
      }

      /// <summary>
      /// Checks for all the available databases...
      /// </summary>
      private void CheckData ()
      {
         DirectoryInfo dirInfo = new DirectoryInfo (Common.DataFolder);
         FileInfo[] files = dirInfo.GetFiles ("*.db", SearchOption.TopDirectoryOnly);
         this.m_ProgramData.BibleDatabases.Clear ();
         this.m_ProgramData.OtherDatabases.Clear ();
         this.m_ProgramData.ReferenceDatabases.Clear ();
         this.m_ProgramData.DailyDatabases.Clear ();
         this.m_ProgramData.Tsk.Name = "";
         this.m_ProgramData.Tsk.Path = "";
         foreach (FileInfo file in files)
         {
            if (file.Name.StartsWith (Common.DATABASE_VERSE_NOTES))
               continue;

            using (SQLiteConnection dbConn = new SQLiteConnection (Common.ConnString (file.FullName)))
            {
               dbConn.Open ();
               SQLiteCommand command = dbConn.CreateCommand ();
               command.CommandText = "SELECT Name, Type, Abbreviation FROM book_info";
               SQLiteDataReader reader = command.ExecuteReader ();
               reader.Read ();

               string name = reader.GetString (reader.GetOrdinal ("Name"));
               string type = reader.GetString (reader.GetOrdinal ("Type"));
               string abbreviation = reader.GetString (reader.GetOrdinal ("Abbreviation"));
               CjData.IcDbInfo dbI = new CjData.IcDbInfo {Name = name, Path = file.Name};
               if (type.Equals (Common.TYPE_BIBLE, StringComparison.CurrentCultureIgnoreCase))
                  this.m_ProgramData.BibleDatabases.Add (dbI);
               else if (type.Equals (Common.TYPE_OTHER, StringComparison.CurrentCultureIgnoreCase) ||
                  type.Equals ("Esoteric", StringComparison.CurrentCultureIgnoreCase))
               {
                  reader.Close ();
                  SQLiteCommand commandBook = dbConn.CreateCommand ();
                  commandBook.CommandText = "SELECT DISTINCT Book FROM book_text";
                  reader = command.ExecuteReader ();

                  while (reader.Read ())
                  {
                     OtherTexts.Add (reader.GetString (0), abbreviation);
                  }
                  this.m_ProgramData.OtherDatabases.Add (dbI);
               }
               else if (type.Equals (Common.TYPE_REFERENCE, StringComparison.CurrentCultureIgnoreCase))
                  this.m_ProgramData.ReferenceDatabases.Add (dbI);
               else if (type.Equals (Common.TYPE_DAILY, StringComparison.CurrentCultureIgnoreCase))
                  this.m_ProgramData.DailyDatabases.Add (dbI);
               else
               {
                  if (type.Equals ("tsk", StringComparison.CurrentCultureIgnoreCase))
                     this.m_ProgramData.Tsk = dbI;
               }
            }
         }
      }

      /// <summary>
      /// Loads the list of bibles...
      /// </summary>
      private void LoadBibles ()
      {
         // Get Results, create menus...
         foreach (CjData.IcDbInfo db in this.m_ProgramData.BibleDatabases)
         {
            ToolStripMenuItem tsmi = new ToolStripMenuItem (db.Name);
            ToolStripMenuItem tsmid = new ToolStripMenuItem (db.Name);

            tsmi.Tag = Common.DataFolder + db.Path;
            tsmid.Tag = Common.DataFolder + db.Path;

            if (tsmid.Text == this.m_ProgramData.DefaultBible)
            {
               tsmid.Checked = true;
            }

            this.m_mnuBibles.DropDownItems.Add (tsmi);
            this.m_mnuToolsDefaultBible.DropDownItems.Add (tsmid);

            tsmi.Click += MnuBibleClick;
            tsmid.Click += SetDefaultBible;
         }

         if (this.m_mnuBibles.DropDownItems.Count == 0)
         {
            this.m_mnuBibles.Visible = false;
         }
      }

      /// <summary>
      /// Loads the list of Other Books...
      /// </summary>
      private void LoadOtherBooks ()
      {
         // Get Results, create menus...
         foreach (CjData.IcDbInfo db in this.m_ProgramData.OtherDatabases)
         {
            ToolStripMenuItem tsmi = new ToolStripMenuItem (db.Name) {Tag = Common.DataFolder + db.Path};

            this.m_mnuOtherBooks.DropDownItems.Add (tsmi);
            tsmi.Click += MnuBibleClick;
         }

         if (this.m_mnuOtherBooks.DropDownItems.Count == 0)
         {
            this.m_mnuOtherBooks.Visible = false;
         }
      }

      /// <summary>
      /// Loads the list of Reference books...
      /// </summary>
      private void LoadReference ()
      {
         // Get Results, create menus...
         foreach (CjData.IcDbInfo db in this.m_ProgramData.ReferenceDatabases)
         {
            ToolStripMenuItem tsmi = new ToolStripMenuItem (db.Name) {Tag = Common.DataFolder + db.Path};

            this.m_mnuReference.DropDownItems.Add (tsmi);
            tsmi.Click += MnuBibleClick;
         }

         if (this.m_mnuReference.DropDownItems.Count == 0)
         {
            this.m_mnuReference.Visible = false;
         }
         else
         {
            this.m_mnuReference.DropDownItems.Add (new ToolStripSeparator ());
            ToolStripMenuItem tsmiSearch = new ToolStripMenuItem ("Search Reference");
            tsmiSearch.Click += RefSearchClick;
            this.m_mnuReference.DropDownItems.Add (tsmiSearch);
         }
      }

      /// <summary>
      /// Loads the list of BookMarks...
      /// </summary>
      private void LoadBookMarks ()
      {
         ((BookMarkDropDown)this._mnuBookMarks.DropDown).BookMarkControl.ClearGrid ();
         foreach (CPassage bm in this.m_ProgramData.BookMarks)
         {
            // Add Book Mark...
            ((BookMarkDropDown)this._mnuBookMarks.DropDown).BookMarkControl.AddBookMark (bm);
         }
         ((BookMarkDropDown)this._mnuBookMarks.DropDown).BookMarkControl.SortGrid ();
      }

      #endregion

      #region - Bible Click -

      /// <summary>
      /// Start a new Bible...
      /// </summary>
      /// <param name="sender">Menu Item</param>
      /// <param name="e">Events</param>
      private void MnuBibleClick (object sender, EventArgs e)
      {
         // Get the menu item...
         ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
         // Add the Page to the main TabberGroup...
         if (tsmi != null) this.m_Tabber.AddTab (new CtrlReader (this, tsmi.Text, tsmi.Tag.ToString ()));
      }

      /// <summary>
      /// Loads a bible...
      /// </summary>
      /// <param name="passages">Passages to load.</param>
      /// <param name="tp">Tabber page to Start.</param>
      public void StartBible (List<CPassage> passages, TabberPage tp)//string book, string chapter, string verse)
      {
         if (passages != null && passages.Count > 0)
         {
            string path = this.GetDbPath (passages[0].Version);
            if (!string.IsNullOrEmpty (path))
            {
               CtrlReader reader = new CtrlReader (this, passages[0].Version, path);
               reader.LoadBookList (false);
               reader.SelectPassages (passages);
               if (tp == null)
                  this.m_Tabber.AddTab (reader);
               else
                  this.m_Tabber.AddTab (reader, tp.Group);
            }
         }
      }

      /// <summary>
      /// Loads a reference...
      /// </summary>
      /// <param name="version">Version to Load.</param>
      /// <param name="word">Word to Lookup.</param>
      /// <param name="tp">Tabber page to start.</param>
      public void StartReference (string version, string word, TabberPage tp)
      {
         string path = "";
         foreach (CjData.IcDbInfo dbi in this.m_ProgramData.ReferenceDatabases)
         {
            if (dbi.Name.Equals (version))
            {
               path = Common.DataFolder + dbi.Path;
               break;
            }
         }
         if (!string.IsNullOrEmpty (path))
         {
            CtrlReader reader = new CtrlReader (this, version, path);
            reader.SelectRefWord (word, false);
            if (tp == null)
               this.m_Tabber.AddTab (reader);
            else
               this.m_Tabber.AddTab (reader, tp.Group);
         }
      }

      /// <summary>
      /// Loads a reference...
      /// </summary>
      /// <param name="version">Version to Load.</param>
      /// <param name="words">Words to Lookup.</param>
      /// <param name="tp">Tabber page to start.</param>
      public void StartReference (string version, string[] words, TabberPage tp)
      {
         string path = "";
         foreach (CjData.IcDbInfo dbi in this.m_ProgramData.ReferenceDatabases)
         {
            if (dbi.Name.Equals (version))
            {
               path = Common.DataFolder + dbi.Path;
               break;
            }
         }
         if (!string.IsNullOrEmpty (path))
         {
            CtrlReader reader = new CtrlReader (this, version, path);
            reader.SelectRefWords (words);
            if (tp == null)
               this.m_Tabber.AddTab (reader);
            else
               this.m_Tabber.AddTab (reader, tp.Group);
         }
      }

      #endregion

      #region - Get Start Tab -

      /// <summary>
      /// Adds a Start Tab to the main Tabber...
      /// </summary>
      private TabberPage GetStartTab ()
      {
         // Create a new TabberPage...
         TabberPage page = new TabberPage ("Start") {ShowCloseButton = false};

         // Add a new Start Control...
         page.Controls.Add (new CtrlStart (this));

         // Add the Page to the main TabberGroup...
         //this.m_Tabber.AddTab(page);
         return page;
      }

      #endregion

      #region - Menu Items -

      /// <summary>
      /// Closes the Application
      /// </summary>
      /// <param name="sender">Exit menu items</param>
      /// <param name="e">Events</param>
      private void MMnuFileExitClick (object sender, EventArgs e)
      {
         // Close this application...
         this.Close ();
      }

      /// <summary>
      /// Option to Save On exit...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MnuSaveOnExitClick (object sender, EventArgs e)
      {
         this.m_ProgramData.SaveLayoutOnExit = this._mnuSaveOnExit.Checked;
      }

      /// <summary>
      /// Option to ask to save on exit...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MnuAskToSaveClick (object sender, EventArgs e)
      {
         this.m_ProgramData.AskSaveLayoutOnExit = this._mnuAskToSave.Checked;
      }

      /// <summary>
      /// Creates a new Note Control...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MnuToolNoteClick (object sender, EventArgs e)
      {
         CtrlNote note = new CtrlNote ();
         this.m_Tabber.AddTab (note);
      }

      /// <summary>
      /// Opens a new Note Tab...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void OpenNoteToolStripMenuItemClick (object sender, EventArgs e)
      {
         if (this._ofdMain.ShowDialog () == DialogResult.OK)
         {
            FileInfo fi = new FileInfo (this._ofdMain.FileName);
            this._ofdMain.InitialDirectory = fi.Directory.FullName;
            CtrlNote note = new CtrlNote ();
            note.OpenFile (fi.FullName);
            this.m_Tabber.AddTab (note);
         }
      }

      /// <summary>
      /// Closes all of the open tabs...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MnuFileCloseAllTabsClick (object sender, EventArgs e)
      {
         for (int a = this.m_Tabber.TabGroups.Count - 1; a >= 0; a--)
         {
            if (this.m_Tabber.TabGroups[a].ContainsTab ("Start"))
            {
               for (int b = this.m_Tabber.TabGroups[a].TabButtons.Count - 1; b >= 0; b--)
               {
                  ((TabButton)this.m_Tabber.TabGroups[a].TabButtons[b]).Page.ClosePage ();
               }
            }
            else
            {
               this.m_Tabber.TabGroups[a].CloseGroup ();
            }
         }
      }

      /// <summary>
      /// Shows the About Form...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">EventArgs</param>
      private void AboutToolStripMenuItemClick (object sender, EventArgs e)
      {
         frmAbout frm = new frmAbout ();
         frm.ShowDialog (this);
      }

      /// <summary>
      /// Shows or Hides Borders around verses...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">EventArgs</param>
      private void MnuToolShowVerseBordersClick (object sender, EventArgs e)
      {
         this.m_ProgramData.ReaderOptions.ShowBorder = !this.m_ProgramData.ReaderOptions.ShowBorder;
         this.UpdateTabs (true, true, false);
      }

      /// <summary>
      /// Highlightes rows on mouse over...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">EventArgs</param>
      private void MnuToolHighlightVerseClick (object sender, EventArgs e)
      {
         this.m_ProgramData.ReaderOptions.HighlightRows = !this.m_ProgramData.ReaderOptions.HighlightRows;
         this.UpdateTabs (true, false, false);
      }

      /// <summary>
      /// Tool Tips will be shown on click...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MnuToolShowTtClickClick (object sender, EventArgs e)
      {
         this._mnuToolShowTTMouseOver.Checked = false;
         this.m_ProgramData.MouseOverToolTips = false;
      }

      /// <summary>
      /// Tool Tips will be shown on mouse over...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MnuToolShowTtMouseOverClick (object sender, EventArgs e)
      {
         this._mnuToolShowTTClick.Checked = false;
         this.m_ProgramData.MouseOverToolTips = true;
      }

      /// <summary>
      /// Opens the default bible...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MnuReadClick (object sender, EventArgs e)
      {
         // Add the Page to the main TabberGroup...
         this.m_Tabber.AddTab (new CtrlReader (this, this.m_ProgramData.DefaultBible, this.DefaultBibleFile));
      }

      /// <summary>
      /// Changes the program font...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MMnuToolFontClick (object sender, EventArgs e)
      {
         this.m_FontDlg.Font = this.m_ProgramData.DefaultFont.ToFont ();
         if (this.m_FontDlg.ShowDialog () == DialogResult.OK)
         {
            this.m_ProgramData.DefaultFont = new CjData.SFont (this.m_FontDlg.Font);
            this.UpdateTabs (true, true, true);
         }
      }

      /// <summary>
      /// Occurs when the help tool menu item is clicked.
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">EventArgs</param>
      private void HelpToolStripMenuItem1Click (object sender, EventArgs e)
      {
         if (File.Exists (Common.DataFolder + Common.HELP_FILE))
            System.Diagnostics.Process.Start (Common.DataFolder + Common.HELP_FILE);
         else
            MessageBox.Show (this, "Help file is missing!", "Jonathan", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }

      #endregion

      #region - Before Page Close -

      /// <summary>
      /// Catches page close events for Tabber...
      /// </summary>
      /// <param name="pe">Page Event Args</param>
      private static void MTabberBeforePageClose (PageEventArgs pe)
      {
         if (pe.Page.TabTitle == "Start")
         {
            pe.Cancel = true;
         }
      }

      #endregion

      #region - Get HTML Header -

      /// <summary>
      /// Gets the Starting string of html to put in all documents.
      /// </summary>
      /// <returns>string of html up to the body start tag</returns>
      public string GetHtmlHeader ()
      {
         System.Text.StringBuilder sb = new System.Text.StringBuilder ();

         sb.Append ("<html><head><title>Jonathan</title>");
         sb.Append ("<style type=\"text/css\">");

         sb.Append ("A:link {text-decoration: underline; color: " + ColorTranslator.ToHtml (Color.DarkRed) + "; }");
         sb.Append ("A:visited {text-decoration: underline; color: " + ColorTranslator.ToHtml (Color.DarkRed) + "; }");
         sb.Append ("A:active {text-decoration: underline; color: " + ColorTranslator.ToHtml (Color.DarkRed) + "; }");
         sb.Append ("A:hover {text-decoration: underline overline; color:  " + ColorTranslator.ToHtml (Color.DarkRed) + "; }");

         sb.Append ("table { border: 1px solid #D4E0EE; border-collapse: collapse; font-family: \"" +
             this.m_ProgramData.DefaultFont.Name + "\", Arial, sans-serif; color: Black; font-size:" +
             Convert.ToString (this.m_ProgramData.DefaultFont.Size + 4) + ";}");
         sb.Append ("th, td { border: " + ((this.m_ProgramData.ReaderOptions.ShowBorder) ? 1 : 0) + "px solid #D4E0EE; border-collapse: collapse; font-family: \"" +
             this.m_ProgramData.DefaultFont.Name + "\", Arial, sans-serif; color: Black; font-size:" +
             Convert.ToString (this.m_ProgramData.DefaultFont.Size + 4) + "; }");

         sb.Append ("caption { font-size: 150%; font-weight: bold; margin: 5px;}");
         sb.Append ("td, th { padding: 4px;}");
         sb.Append ("td.passage { color: " + ColorTranslator.ToHtml (Color.DarkRed) + "; font-weight:bold;}");
         sb.Append ("thead th { text-align: center; background: #FCFDFE; color: Black; font-size: 100% !important;}");
         sb.Append ("tbody th {font-weight: bold;}");
         sb.Append ("tbody tr { background: #FCFDFE; }");
         sb.Append (".normalRow { background: #FCFDFE; }");
         sb.Append (".goto {text-decoration: underline; color: " + ColorTranslator.ToHtml (Color.DarkRed) + "; }");

         sb.Append (this.m_ProgramData.ReaderOptions.HighlightRows
                       ? ".highliteRow { background: yellow; }"
                       : ".highliteRow { background: #FCFDFE; }");

         sb.Append ("table.search { cursor: default; }");
         sb.Append ("tfoot th, tfoot td { font-size: 85%; }");

         sb.Append ("#reader { border: 1px solid gray; width: 450px; position: absolute; left: 0px; top: 0px; background: #FCFDFE;}");
         sb.Append ("#readerTitles { border: 1px solid gray; background: #FCFDFE;}");
         sb.Append ("#innerReader { height: 500px; overflow: auto;}");

         sb.Append ("</style>");

         sb.Append ("<script type=\"text/javascript\">");

         // Resize...
         sb.Append ("function resizeJonathan()");
         sb.Append ("{");
         sb.Append ("var theWidth, theHeight;");
         sb.Append ("if (window.innerWidth)");
         sb.Append ("{");
         sb.Append ("theWidth = window.innerWidth;");
         sb.Append ("}");
         sb.Append ("else if (document.documentElement && document.documentElement.clientWidth)");
         sb.Append ("{");
         sb.Append ("theWidth = document.documentElement.clientWidth;");
         sb.Append ("}");
         sb.Append ("else if (document.body)");
         sb.Append ("{");
         sb.Append ("theWidth = document.body.clientWidth;");
         sb.Append ("}");
         sb.Append ("if (window.innerHeight)");
         sb.Append ("{");
         sb.Append ("theHeight = window.innerHeight;");
         sb.Append ("}");
         sb.Append ("else if (document.documentElement && document.documentElement.clientHeight)");
         sb.Append ("{");
         sb.Append ("theHeight = document.documentElement.clientHeight;");
         sb.Append ("}");
         sb.Append ("else if (document.body)");
         sb.Append ("{");
         sb.Append ("theHeight = document.body.clientHeight;");
         sb.Append ("}");
         sb.Append ("var read = document.getElementById('reader');");
         sb.Append ("var readTitles = document.getElementById('readerTitles');");
         sb.Append ("var innerRead = document.getElementById('innerReader');");
         sb.Append ("if (read != null){");
         sb.Append ("innerRead.style.height = theHeight - readTitles.offsetHeight;");
         sb.Append ("innerRead.style.width = theWidth;");
         sb.Append ("read.style.width = theWidth;");
         sb.Append ("readTitles.style.width = theWidth;");
         sb.Append ("}");
         sb.Append ("}");

         sb.Append ("function getTextSelection()");
         sb.Append ("{");
         sb.Append ("var tRange = document.selection.createRange();");
         sb.Append ("var txt = tRange.text;");
         sb.Append ("return txt;");
         sb.Append ("}");

         sb.Append ("function expandSelection()");
         sb.Append ("{");
         sb.Append ("var x = window.event.clientX;");
         sb.Append ("var y = window.event.clientY;");
         sb.Append ("var tRange = document.selection.createRange();");
         sb.Append ("tRange.collapse();");
         sb.Append ("tRange.moveToPoint(x, y);");
         sb.Append ("tRange.expand('word');");
         sb.Append ("tRange.select();");
         //sb.Append("return tRange.text;");
         sb.Append ("}");

         sb.Append ("var tRange = null;");
         sb.Append ("function findString(strToFind)");
         sb.Append ("{");
         sb.Append ("var strFound;");
         sb.Append ("if (tRange != null)");
         sb.Append ("{");
         sb.Append ("tRange.collapse(false);");
         sb.Append ("strFound = tRange.findText(strToFind);");
         sb.Append ("if (strFound) tRange.select();");
         sb.Append ("}");
         sb.Append ("if (tRange == null || strFound == 0)");
         sb.Append ("{");
         sb.Append ("tRange = document.body.createTextRange();");
         sb.Append ("strFound = tRange.findText(strToFind);");
         sb.Append ("if (strFound) tRange.select();");
         sb.Append ("}");
         sb.Append ("}");

         sb.Append ("window.onresize = resizeJonathan;");
         sb.Append ("</script>");

         sb.Append ("</head><body onload=\"resizeJonathan();\" style=\" background: White; color: Black; font-family: \"" +
             this.Font.Name + "\", Arial, sans-serif; font-size:" + Convert.ToString (this.Font.Size + 4) + ";\">");

         return sb.ToString ();
      }

      #endregion

      #region - Search -

      /// <summary>
      /// Starts a search...
      /// </summary>
      /// <param name="sender">Button</param>
      /// <param name="e">Events</param>
      private void MBtnSearchClick (object sender, EventArgs e)
      {
         this.Search (this.m_txtSearch.Text);
      }

      /// <summary>
      /// Starts a search...
      /// </summary>
      /// <param name="sender">TextBox</param>
      /// <param name="e">Key Events</param>
      private void MTxtSearchKeyUp (object sender, KeyEventArgs e)
      {
         if (e.KeyCode == Keys.Enter)
         {
            this.Search (this.m_txtSearch.Text);
         }
      }

      /// <summary>
      /// Creates a new search control, and searches for the given text...
      /// </summary>
      /// <param name="text"></param>
      public void Search (string text)
      {
         // Create a search control...
         CtrlSearch sControl = new CtrlSearch (this, Common.TYPE_BIBLE);

         // Add the Page to the main TabberGroup...
         this.m_Tabber.AddTab (sControl);

         if (text.Trim () != string.Empty)
         {
            sControl.Search (text);
         }
      }

      /// <summary>
      /// Creates a new search control, and searches for the given text...
      /// </summary>
      /// <param name="text">Text to lookup.</param>
      /// <param name="type">Type of Search.</param>
      /// <param name="oldpage">TabberPage request is comming from.</param>
      public void Search (string text, TabberPage oldpage, string type)
      {
         // Create a search control...
         CtrlSearch sControl = new CtrlSearch (this, type);

         // Add the Page to the main TabberGroup...
         this.m_Tabber.AddTab (oldpage.Group, sControl, Tabber.Tabber.TabDockStyle.Right);

         if (text.Trim () != string.Empty)
         {
            sControl.Search (text);
         }
      }

      /// <summary>
      /// Creates a new search control, and searches for the given text...
      /// </summary>
      /// <param name="version">Bible Version to Look in.</param>
      /// <param name="text">Text to lookup.</param>
      /// <param name="oldpage">TabberPage request is comming from.</param>
      public void Search (string version, string text, TabberPage oldpage)
      {
         // Create a search control...
         CtrlSearch sControl = new CtrlSearch (this, Common.TYPE_BIBLE);
         sControl.ChangeVersion (version);

         // Add the Page to the main TabberGroup...
         this.m_Tabber.AddTab (oldpage.Group, sControl, Tabber.Tabber.TabDockStyle.Right);

         if (text.Trim () != string.Empty)
         {
            sControl.Search (text);
         }
      }

      /// <summary>
      /// Creates a Search Control...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void SearchToolStripMenuItemClick (object sender, EventArgs e)
      {
         // Create a search control...
         CtrlSearch sControl = new CtrlSearch (this, Common.TYPE_BIBLE);

         // Add the Page to the main TabberGroup...
         this.m_Tabber.AddTab (sControl);
      }

      #endregion

      #region - Closing -

      /// <summary>
      /// Occurs before closing...
      /// </summary>
      /// <param name="e">Closing Events</param>
      protected override void OnClosing (CancelEventArgs e)
      {
         // Ask About Saving Tabber Layout...
         if (this.m_ProgramData.AskSaveLayoutOnExit)
         {
            frmExit exit = new frmExit (this);
            if (exit.ShowDialog (this) == DialogResult.Cancel)
            {
               e.Cancel = true;
            }
         }

         if (!e.Cancel)
         {
            // We can empty these, because we re-check on startup...
            this.m_ProgramData.ReferenceDatabases.Clear ();
            this.m_ProgramData.OtherDatabases.Clear ();
            this.m_ProgramData.BibleDatabases.Clear ();
            this.m_ProgramData.DailyDatabases.Clear ();

            // Save some data...
            this.m_ProgramData.Size = this.Size;
            this.m_ProgramData.Location = this.Location;
            this.m_ProgramData.WindowState = this.WindowState;

            // Save Tabber Layout...
            try
            {
               if (File.Exists (this.m_ProgramData.TabLayoutFile))
                  File.Delete (this.m_ProgramData.TabLayoutFile);
               this.m_ProgramData.TabLayoutFile = "";

               if (this.m_ProgramData.SaveLayoutOnExit)
               {
                  this.m_ProgramData.TabLayoutFile = Common.DataFolder + Path.GetRandomFileName ();
                  this.m_Tabber.SaveLayout (this.m_ProgramData.TabLayoutFile);
               }
            }
            catch (IOException ex)
            {
               Console.WriteLine (ex.Message);
            }

            using (StreamWriter sr = new StreamWriter (Common.DataFolder + Common.FILE_PROGRAM_DATA))
            {
               XmlSerializer ser = new XmlSerializer (typeof (CjData));
               ser.Serialize (sr, this.m_ProgramData);
            }
         }

         base.OnClosing (e);
      }

      #endregion

      #region - Passage Finder -

      /// <summary>
      /// Starts the Passage Finder with the given passages...
      /// </summary>
      /// <param name="sender">ToolStripButton</param>
      /// <param name="e">Events</param>
      private void MBtnFindPassageClick (object sender, EventArgs e)
      {
         CtrlSearch search = new CtrlSearch (this, Common.TYPE_PASSAGE);
         if (!string.IsNullOrEmpty (this.m_txtJump.Text.Trim ()))
         {
            search.Search (this.m_txtJump.Text.Trim ());
         }
         this.m_Tabber.AddTab (search);
      }

      /// <summary>
      /// Starts the Passage Finder with the given passages...
      /// </summary>
      /// <param name="sender">TextBox</param>
      /// <param name="e">Events</param>
      void FindPassagesKeyDown (object sender, KeyEventArgs e)
      {
         if (e.KeyCode == Keys.Enter)
            this.MBtnFindPassageClick (sender, null);
      }

      /// <summary>
      /// Starts the Passage Finder...
      /// </summary>
      /// <param name="sender">ToolStripMenuItem</param>
      /// <param name="e">Events</param>
      private void MMnuToolsPassageFinderClick (object sender, EventArgs e)
      {
         CtrlSearch search = new CtrlSearch (this, Common.TYPE_PASSAGE);
         this.m_Tabber.AddTab (search);
      }

      #endregion

      #region - Reference Lookup -

      /// <summary>
      /// Looksup the reference text...
      /// </summary>
      /// <param name="sender">ToolStripButton</param>
      /// <param name="e">Events</param>
      private void MBtnLookupGoClick (object sender, EventArgs e)
      {
         CtrlSearch search = new CtrlSearch (this, Common.TYPE_REFERENCE);
         this.m_Tabber.AddTab (search);

         if (!string.IsNullOrEmpty (this.m_txtLookup.Text.Trim ()))
         {
            search.Search (this.m_txtLookup.Text);
         }
      }

      /// <summary>
      /// Check for enter pressed in Reference lookup text box...
      /// </summary>
      /// <param name="sender">ToolStripTextBox</param>
      /// <param name="e">Events</param>
      void TxtLookUpKeyDown (object sender, KeyEventArgs e)
      {
         if (e.KeyCode == Keys.Enter)
            this.MBtnLookupGoClick (sender, null);
      }

      /// <summary>
      /// Opens the Reference Search...
      /// </summary>
      /// <param name="sender">ToolStripMenuItesm</param>
      /// <param name="e">Events</param>
      void RefSearchClick (object sender, EventArgs e)
      {
         CtrlSearch search = new CtrlSearch (this, Common.TYPE_REFERENCE);
         this.m_Tabber.AddTab (search);
      }

      #endregion

      #region - Misc -

      /// <summary>
      /// Update the tabs...
      /// </summary>
      /// <param name="reader">Update Readers or Not</param>
      /// <param name="search">Update searches or Not</param>
      /// <param name="start">Update start or Not</param>
      private void UpdateTabs (bool reader, bool search, bool start)
      {
         foreach (TabberGroup tg in this.m_Tabber.TabGroups)
         {
            foreach (TabButton btn in tg.TabButtons)
            {
               if (btn.Page.GetType () == typeof (CtrlReader) && reader)
               {
                  ((CtrlReader)btn.Page).UpdateText ();
               }
               else if (btn.Page.GetType () == typeof (CtrlSearch) && search)
               {
                  ((CtrlSearch)btn.Page).UpdateFont ();
               }
               else if (btn.ButtonText.Equals ("Start") && start)
               {
                  ((CtrlStart)btn.Page.Controls[0]).UpdateFont ();
               }
            }
         }
      }

      /// <summary>
      /// Gets the Path to the given datbase..
      /// </summary>
      /// <param name="dbName">Name of Database.</param>
      /// <returns>Path to database.</returns>
      public string GetDbPath (string dbName)
      {
         List<CjData.IcDbInfo> sources = new List<CjData.IcDbInfo> ();
         sources.AddRange (this.m_ProgramData.BibleDatabases);
         sources.AddRange (this.m_ProgramData.OtherDatabases);
         sources.AddRange (this.m_ProgramData.ReferenceDatabases);

         return (from dbi in sources where dbi.Name.Equals (dbName) select Common.DataFolder + dbi.Path).FirstOrDefault ();
      }

      /// <summary>
      /// Gets the Name to the given datbase..
      /// </summary>
      /// <param name="dbPath">Path to Database.</param>
      /// <returns>Name of database.</returns>
      public string GetDbName (string dbPath)
      {
         List<CjData.IcDbInfo> sources = new List<CjData.IcDbInfo> ();
         sources.AddRange (this.m_ProgramData.BibleDatabases);
         sources.AddRange (this.m_ProgramData.OtherDatabases);
         sources.AddRange (this.m_ProgramData.ReferenceDatabases);

         return (from dbi in sources where Common.DataFolder + dbi.Path == dbPath select dbi.Name).FirstOrDefault ();
      }

      /// <summary>
      /// Gets an Internal Image...
      /// </summary>
      /// <param name="imageName">Name of Image to Get.</param>
      /// <returns>Image.</returns>
      public Image GetInternalImage (string imageName)
      {
         Assembly assem = this.GetType ().Assembly;
         System.Resources.ResourceManager mngr = new System.Resources.ResourceManager ("Jonathan.InternalImages", assem);
         Image img = (Image)mngr.GetObject (imageName);
         return img;
      }

      /// <summary>
      /// Occurs when the Tab Panel is Double Clicked...
      /// </summary>
      /// <param name="tabberGroup">Group for Panel that is double Clicked.</param>
      /// <param name="e">MouseEventArgs</param>
      void MTabberTabPanelDoubleClick (TabberGroup tabberGroup, MouseEventArgs e)
      {
         this.m_Tabber.AddTab (new CtrlReader (this, this.m_ProgramData.DefaultBible, this.DefaultBibleFile), tabberGroup);
      }

      #endregion

      #region -= Book Marks =-

      /// <summary>
      /// Adds the given book mark...
      /// </summary>
      /// <param name="bmInfo">Info for book mark.</param>
      public void AddBookMark (string bmInfo)
      {
         string[] parsedInfo = bmInfo.Split ('|');
         CPassage bm = new CPassage (parsedInfo[0], parsedInfo[1], parsedInfo[2], parsedInfo[3]);
         this.m_ProgramData.BookMarks.Add (bm);
         this.LoadBookMarks ();
      }

      /// <summary>
      /// Removes the given book mark from the list...
      /// </summary>
      /// <param name="bm">Book Mark to Remove...</param>
      public void RemoveBookMark (CPassage bm)
      {
         if (MessageBox.Show (this, "Do you really want to delete the Book Mark for " + bm + "?", "Jonathan",
             MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
         {
            this.m_ProgramData.BookMarks.Remove (bm);
            this.LoadBookMarks ();
         }
      }

      #endregion

      private void doSomethingToolStripMenuItem_Click (object sender, EventArgs e)
      {
         using (SQLiteConnection dbConn = new SQLiteConnection(Common.ConnString ("D:\\My Stuff\\Jonathan\\Unveiled_Mysteries.db")))
         {
            using (StreamReader sr = new StreamReader ("D:\\My Stuff\\Jonathan\\Unveiled Mysteries.txt"))
            {
               int chapter = 0;
               int verse = 0;
               string header = string.Empty;
               dbConn.Open ();
               SQLiteTransaction transaction = dbConn.BeginTransaction ();
               SQLiteCommand command = dbConn.CreateCommand ();
               while (sr.Peek () != -1)
               {
                  string line = sr.ReadLine ();
                  if (!string.IsNullOrEmpty (line))
                  {
                     line = line.Trim ();
                     if (line.StartsWith ("<p>", StringComparison.CurrentCultureIgnoreCase))
                     {
                        verse++;
                        command.CommandText = string.Format ("INSERT INTO book_text (Book, Chapter, Verse, Text, Header, Footer, Notes) " +
                           "VALUES ('Unveiled Mysteries', {0}, {1}, '{2}', '{3}', '', '')", chapter, verse,
                           line.Replace ("<p>", "").Replace ("</p>", "").Replace ("'", "''"), header.Replace ("'", "''"));
                        header = string.Empty;
                        command.ExecuteNonQuery ();
                     }
                     else
                     {
                        chapter++;
                        verse = 0;
                        header = line;
                     }
                  }
               }
               transaction.Commit ();
            }
         }
      }

      /*/// <summary>
        /// Gets the title of the abbreveation of other books...
        /// </summary>
        /// <param name="book">Book abbreveation</param>
        /// <returns>Full Book Name</returns>
        public static string GetOtherBook (string book)
        {
            foreach (cJData.icDBInfo dbI in this.m_ProgramData.OtherDatabases)
            {
                Database db = new Database(dbI.Path);
                Query qBookList = new Query(QueryType.SELECT, Common.TABLE_BOOK_LIST);
                qBookList.SELECT("*");
                db.RunQuery(qBookList);

                for (int a = 0; a < qBookList.RowsReturned; a++)
                {
                    string book = "";
                    string[] spBook = qBookList.Results.GetFieldString(0, a).Split(' ');
                    foreach (string b in spBook)
                    {
                        if (Char.IsLetter(b[0]))
                            book += b[0].ToString().ToUpper();
                    }
                }
            }
        }*/
   }
}